#include <errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
#include <linux/config.h>
#include <sys/utsname.h>
#include <sys/param.h>
#include <sys/time.h>
#include <asm/segment.h>
#include <string.h>

struct timezone sys_tz = { 0, 0};

int sys_ftime() {
    return -ENOSYS;
}

int sys_break() {
    return -ENOSYS;
}

int sys_ptrace() {
    return -ENOSYS;
}

int sys_stty() {
    return -ENOSYS;
}

int sys_gtty() {
    return -ENOSYS;
}

int sys_prof() {
    return -ENOSYS;
}

int sys_setregid(int rgid, int egid) {
    if (rgid>0) {
        if ((current->gid == rgid) ||
                suser())
            current->gid = rgid;
    }
    else {
        return(-EPERM);
    }

    if (egid>0) {
        if ((current->gid == egid) ||
                (current->egid == egid) ||
                suser()) {
            current->egid = egid;
            current->sgid = egid;
        }
        else {
            return(-EPERM);
        }
    }

    return 0;
}

int sys_setgid(int gid) {
    if (suser())
        current->gid = current->egid = current->sgid = gid;
    else if ((gid == current->gid) || (gid == current->sgid))
        current->egid = gid;
    else
        return -EPERM;
    return 0;
}

int sys_setsid() {
    if (current->leader && !suser())
        return -EPERM;
    current->leader = 1;
    current->session = current->pgrp = current->pid;
    current->tty = -1;

    return current->pgrp;
}

int sys_rename() {
    return -ENOSYS;
}

int sys_acct() {
    return -ENOSYS;
}

int sys_phys() {
    return -ENOSYS;
}

int sys_lock() {
    return -ENOSYS;
}

int sys_mpx() {
    return -ENOSYS;
}

int sys_time(long * tloc) {
    int i;
    i = CURRENT_TIME;
    if (tloc) {
        put_fs_long(i,(unsigned long *)tloc);
    }
    return i;
}

int sys_gettimeofday(struct timeval *tv, struct timezone *tz) {
    if (tv) {
        verify_area(tv, sizeof *tv);
        put_fs_long(startup_time + CT_TO_SECS(jiffies),
                (unsigned long *) tv);
        put_fs_long(CT_TO_USECS(jiffies),
                ((unsigned long *) tv)+1);
    }

    if (tz) {
        verify_area(tz, sizeof *tz);
        put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
        put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
    }
    return 0;
}

int sys_ulimit() {
    return -ENOSYS;
}

int sys_getgroups(int gidsetsize, gid_t *grouplist) {
    int     i;
    if (gidsetsize)
        verify_area(grouplist, sizeof(gid_t) * gidsetsize);
    for (i = 0; (i < NGROUPS) && (current->groups[i] != NOGROUP);
            i++, grouplist++) {
        if (gidsetsize) {
            if (i >= gidsetsize)
                return -EINVAL;
            put_fs_word(current->groups[i], (short *) grouplist);
        }
    }
    return i;
}

int sys_brk(unsigned long end_data_seg) {
    if (end_data_seg >= current->end_code &&
            end_data_seg < current->start_stack - 16384)
        current->brk = end_data_seg;
    return current->brk;
}

int in_group_p(gid_t grp) {
    int i;
    if (grp == current->egid)
        return 1;

    /*
    for (i = 0; i < NGROUPS; i++) {
        if (current->groups[i] == NOGROUP)
            break;
        if (current->groups[i] == grp)
            return 1;
    }*/

    return 0;
}

static struct utsname thisname = {
    UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, UTS_MACHINE
};

int sys_uname(struct utsname * name) {
    int i;

    if (!name) return -ERROR;
    verify_area(name, sizeof(*name));
    for(i = 0; i < sizeof(*name); i++)
        put_fs_byte(((char *) &thisname)[i],i+(char *) name);
    return 0;
}

int sys_setuid(int uid) {
    if (suser())
        current->uid = current->euid = current->suid = uid;
    else if ((uid == current->uid) || (uid == current->suid))
        current->euid = uid;
    else
        return -EPERM;
    return 0;
}

int sys_stime(long * tptr) {
    printk("unimplement sys call stime\n");
    return 0;
}


int sys_umask(int mask) {
    int old = current->umask;

    current->umask = mask & 0777;
    return (old);
}

